/*
 * @Author: hyq
 * @Date: 2023-12-5 10:34:34
 */
import { ref, computed, onActivated, onDeactivated, onBeforeUnmount } from 'vue'
import { isH5 } from '@/utils'

const counter: any =
  typeof requestAnimationFrame == 'function' && isH5
    ? requestAnimationFrame
    : setTimeout

const cancelCounter: any =
  typeof cancelAnimationFrame == 'function' && isH5
    ? cancelAnimationFrame
    : clearTimeout

export type CurrentTime = {
  days: number
  hours: number
  total: number
  minutes: number
  seconds: number
  milliseconds: number
}

const SECOND = 1000
const MINUTE = 60 * SECOND
const HOUR = 60 * MINUTE
const DAY = 24 * HOUR

/**
 * 转换时间对象
 * @param time
 * @returns
 */
function parseTime(time: number): CurrentTime {
  const days = Math.floor(time / DAY)
  const hours = Math.floor((time % DAY) / HOUR)
  const minutes = Math.floor((time % HOUR) / MINUTE)
  const seconds = Math.floor((time % MINUTE) / SECOND)
  const milliseconds = Math.floor(time % SECOND)

  return {
    total: time,
    days,
    hours,
    minutes,
    seconds,
    milliseconds
  }
}

function isSameSecond(time1: number, time2: number): boolean {
  return Math.floor(time1 / 1000) === Math.floor(time2 / 1000)
}

export function useCountDown(options: {
  time: number
  millisecond?: boolean
  onChange?: (current: CurrentTime) => void
  onFinish?: () => void
}) {
  let rafId: number
  let endTime: number
  let deactivated: boolean

  const counting = ref<boolean>(false)
  const remain = ref(options.time)
  const current = computed(() => parseTime(remain.value))

  // 暂停
  const pause = () => {
    counting.value = false
    cancelCounter(rafId)
  }

  // 获取当前 计时时间
  const getCurrentRemain = () => Math.max(endTime - Date.now(), 0)

  // 设置变更后的计时时间
  const setRemain = (value: number) => {
    remain.value = value
    options.onChange?.(current.value)
    if (value === 0) {
      pause()
      options.onFinish?.()
    }
  }

  // 微任务
  const microTick = () => {
    rafId = counter(() => {
      // in case of call reset immediately after finish
      if (counting.value) {
        setRemain(getCurrentRemain())
        if (remain.value > 0) {
          microTick()
        }
      }
    })
  }

  // 宏任务
  const macroTick = () => {
    counter(() => {
      // in case of call reset immediately after finish
      if (counting.value) {
        const remainRemain = getCurrentRemain()

        // 当秒级变化后才更新
        if (!isSameSecond(remainRemain, remain.value) || remainRemain === 0) {
          setRemain(remainRemain)
        }

        if (remain.value > 0) {
          macroTick()
        }
      }
    })
  }

  // 秒级变化还是毫秒级 requestAnimationFrame 比 setTimeout或者setInterval
  const tick = () => {
    if (options.millisecond) {
      microTick()
    } else {
      macroTick()
    }
  }

  // 开始
  const start = () => {
    if (!counting.value) {
      endTime = Date.now() + remain.value
      counting.value = true
      tick()
    }
  }

  // 重置
  const reset = (totalTime: number = options.time) => {
    pause()
    remain.value = totalTime
  }

  onBeforeUnmount(pause)

  onActivated(() => {
    if (deactivated) {
      counting.value = true
      deactivated = false
      tick()
    }
  })

  onDeactivated(() => {
    if (counting.value) {
      pause()
      deactivated = true
    }
  })

  return {
    start,
    pause,
    reset,
    current,
    counting
  }
}
